#!/usr/bin/env python

#    Titan Music Player
#    Copyright (C) 2008  Chris "vbraun" Dopilka
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import curses, threading
import random, cPickle
import gobject
import pygst
pygst.require("0.10")
import gst
import signal
import sys
from time import sleep

import lib



class MyError(Exception):
	def __init__(self,value):
		self.value = value
	def __str__(self):
		return repr(self.value)

class interface(threading.Thread):
	def __init__(self,audio):
		threading.Thread.__init__(self)
		
		self.audio = audio
		self.audio.stdscr = curses.initscr()
		self.audio.h, self.audio.w = self.audio.stdscr.getmaxyx()
		self.audio.window = curses.newwin(self.audio.h-1, self.audio.w, 1,0)
		
	def run(self):
		while 1:
			try:
				c = self.audio.stdscr.getkey()
				self.audio.input(c)
				
				sleep(0.05)
			except Exception, e:
				if str(e) != "no input":
					self.audio.stdscr.addstr(self.audio.h - 1,0,str(Exception) + str(e))
				sleep(0.05)

class audio(interface):

	class now_playing():
		def __init__(self):
			self.majorTags = []
			self.minorTags = []
			self.filename = "False"
	
	def __init__(self,args,dirReal,tagList):
		self. stdscr = curses.initscr()
		self.interface = interface(self)
		self.h, self.w = self.stdscr.getmaxyx()
		self.window = curses.newwin(self.h-1, self.w, 1,0)
		self.stdscr.nodelay(1)
		
		self.stdscr.keypad(1)
		curses.noecho()

		self.library = lib.Library(args,dirReal,tagList)
		
		self.status = "False"
		self.playing = self.now_playing()
		self.song_list = []

		self.playing.majorTags = ["Stravinksy", "Three Pieces for Solo Clarinet"]
		self.playing.minorTags = ["3", "None"]
		self.filepath = "/home/chris/python/titan/strav3.ogg"

	def on_message(self,bus,message):
		if message == "first":
			t = gst.MESSAGE_EOS
			self.notFirst = False
		elif message == "skip":
			t = gst.MESSAGE_EOS
		else:
			t = message.type
			self.notFirst = True
			

		
		if t == gst.MESSAGE_EOS:
			self.player.set_state(gst.STATE_NULL)
			if len(self.song_list) == 0:
				self.song_list, self.display_list = self.pickSong()
			self.playFile()
		
		elif t ==  gst.MESSAGE_ERROR:
			self.player.set_state(gst.STATE_NULL)
			self.error_display('gst.MESSAGE_ERROR', 'on_message')
	
	def playFile(self):
		self.filepath = self.song_list.pop()
		if self.display_list:
			display = self.display_list.pop()
			self.playing.majorTags = display[0].split(";,")
			self.playing.minorTags = display[1].split(";,")
		self.player.set_property('uri', "file://" + self.filepath)
		self.player.set_state(gst.STATE_PLAYING)
		self.status = "playing"
		self.stdscr.erase()
		if self.notFirst:
			self.display_infobox()
			self.display_statusbox()
		
	def createPlayer(self):
		self.player = gst.element_factory_make("playbin", "player")
		self.fakesink = gst.element_factory_make('fakesink', "my-fakesink")
		self.player.set_property("video-sink", self.fakesink)
		self.bus = self.player.get_bus()
		self.bus.add_signal_watch()
		self.bus.connect('message',self.on_message)
		self.player.set_state(gst.STATE_NULL)
		#~ self.player.set_property('uri', "file://" + self.filepath)		
		#~ self.player.set_state(gst.STATE_PLAYING)
		#~ self.status = "playing"
		self.stdscr.erase()
	
	def betterRandom(self):
		try:
			file = open('notPlayed.txt','rb')
			notPlayed = cPickle.load(file)
			file.close()
		except:
			print "opening notPlayed.txt failed"
			notPlayed = False
		if notPlayed is False:
			notPlayed = self.library.randomDict.keys()
		try:
			thePick = random.choice(notPlayed)
		except:
			notPlayed = self.library.randomDict.keys()
			thePick = random.choice(notPlayed)
		notPlayed.pop(notPlayed.index(thePick))
		file = open('notPlayed.txt','w')
		cPickle.dump(notPlayed,file)
		file.close()
		return thePick
			
	def pickSong(self):
		item_list = []
		display_list = []
		thePick = self.betterRandom()
		for item in self.library.randomDict[thePick]:
			tags = item.split(u';,')
			item_list[:0] = [tags[-1]]
			display = thePick, tags[0] + u';,' + tags[1] 
			display_list.append(display)
			display_list.sort()
			display_list.reverse()
		return item_list, display_list
		

	def run(self):
		self.interface.start()
		
	def input(self,c):
#		self.stdscr.addstr(0,0,"TITAN               ")
#		self.stdscr.addstr(1,0,str(self.player.get_state()))
		if c == 'p':
			if self.status == "playing":
				self.player.set_state(gst.STATE_PAUSED)
				self.status = "paused"
			#~ elif gst.STATE_NULL == current_state:
				#~ self.player.set_property('uri', "file://" + self.filepath)
				#~ self.stdscr.addstr(0,0,"Playing")
				#~ self.status = "playing"
				#~ self.player.set_state(gst.STATE_PLAYING)
			elif self.status == "paused":
				self.player.set_state(gst.STATE_PLAYING)
				self.status = "playing"
				
			self.display_statusbox()
		elif c == 'KEY_RIGHT': 
			self.on_message(False,"skip")
		elif c == 'd': 
			self.display_infobox()
		elif c == 'r':
			self.stdscr.refresh()
			self.display_statusbox()
			self.display_infobox()
		elif c == 'q':
			self.shutdown()
		else:
			raise MyError(c)
		self.stdscr.refresh()
	
	def error_display(self,e,errorCameFrom):
		try:
			display = "Error: " + errorCameFrom + ": " + str(e)
			self.stdscr.addstr(self.h - 2, 0, display)
		except Exception, e:
			self.stdscr.addstr(0,0,str(e))

	def display_infobox(self):
		try:
			self.infobox.erase()
#			self.infobox.idlok(1)
#			self.infobox.scrollok(1)
			i = 0
			for tag in self.playing.majorTags:
				self.infobox.addstr(i,0,str(tag))
				i = i + 1
			display = ""
			for tag in self.playing.minorTags:
				display = display + tag + " "
			self.infobox.addstr(i,2,display)
		except Exception, e:
			self.error_display(e,"display_infobox")
		self.infobox.refresh()

	def display_statusbox(self):
		try:
			self.statusbox.erase()
			self.statusbox.idlok(1)
			self.statusbox.scrollok(1)
			self.statusbox.addstr("%s" %self.status)
		except Exception, e:
			self.error_display(e,"display_statusbox")
		self.statusbox.refresh()
	

	def create_infobox(self):
		try:
			self.infobox = curses.newwin(5,self.w,5,0)
			self.infobox.idlok(1)
			self.infobox.scrollok(1)
			self.infobox.erase()
			self.display_infobox()
		except Exception, e:
			self.error_display(e,"create_infobox")

	def create_statusbox(self):
		try:
			self.statusbox = curses.newwin(3,self.w,1,0)
			self.statusbox.idlok(1)
			self.statusbox.scrollok(1)
			self.statusbox.erase()
			self.display_statusbox()
			
		except Exception, e:
			self.error_display(e,"create_statusbox")
	
	#~ def create_blankbox(self):
		#~ try:
			#~ self.blankbox = curses.newwin(20, self.w, 1,0)
			#~ self.blankbox.idlok(1)
			#~ self.blankbox.scrollok(1)
			#~ self.blankbox.erase()
			#~ self.blankbox.addstr("HAI ")
		#~ except Exception, e:
			#~ self.error_display(e,"create_blankbox")

	def shutdown(self):
		self.player.set_state(gst.STATE_NULL)
		curses.nocbreak()
		self.stdscr.keypad(0)
		curses.echo()
		curses.endwin()
		sys.exit(1)
	
	def build(self, stdscr):
		self.stdscr = stdscr

		self.createPlayer()
		self.on_message(False,'first')
		self.stdscr.erase()
		self.stdscr.refresh()
		self.stdscr.nodelay(1)

		self.h, self.w = self.stdscr.getmaxyx()
#		self.create_blankbox()
		self.create_statusbox()
		self.create_infobox()

class MainApp:
	def __init__(self,args,dirReal,tagList):
		self.app = audio(args,dirReal,tagList)
	
	def MainLoop(self):
		signal.signal(signal.SIGINT, self.die)
		self.app.build(self.app.stdscr)
		Mapp.app.interface.start()
		mainloop = gobject.MainLoop()
		mainloop.run()
		
	def die(self, w, e):
		self.app.shutdown()

try:
	args = sys.argv[1]
	print args
except:
	args = False
	
#Edit these accordingly
#dirReal = main folder for music, will check in subfolders
dirReal = '/home/chris/python/titan'
#tagList = list of tags that matter; 
#first two are put as keys into a dictionary and then randomly chosen from
#last two are used to sort it
tagList = ["composer","main title","movement number","movement"]


gobject.threads_init()

Mapp = MainApp(args,dirReal,tagList)

try:
	Mapp.MainLoop()

except Exception, e:

	try:
		curses.echo()
		curses.nocbreak()
		curses.endwin()
	except:
		pass
	print e